﻿#include "requesttask.h"
#include "base/basetype.h"
#include "base/utils/utils.h"
#include "requestqueue.h"
#include <QCryptographicHash>
#include <QHttpMultiPart>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QSslConfiguration>
#include <QtDebug>
#include <QUrl>

namespace yc {

RequestTask::RequestTask(const Request& request, const ResponseHandler& handler,
                         RequestQueue* queue, const RequestHeaders& global_headers, bool log,
                         int timeout)
    : Task(request.seq(), true, timeout, queue),
      queue_(queue),
      global_headers_(global_headers),
      request_(request),
      handler_(handler),
      reply_(nullptr),
      log_(log),
      completed_(false)
{
}

RequestTask::~RequestTask()
{
    if (reply_) {
        if (reply_->isRunning()) {
            reply_->abort();
        }
        delete reply_;
        reply_ = nullptr;
    }

    if (isRunning() && !completed_) {
        completed_ = true;
        // 停止超时计时器
        stopTimeoutTimer();
        Response resp(CANCEL_ERROR, tr("User canceled."));
        onResponse(request_, resp);
    }
}

void RequestTask::startImpl()
{
    // send request
    QNetworkRequest request;

    // // ssl
    // if (request_.url().startsWith("https", Qt::CaseInsensitive)) {
    //     QSslConfiguration ssl_config;
    //     ssl_config.setPeerVerifyMode(QSslSocket::VerifyNone);
    //     ssl_config.setProtocol(QSsl::TlsV1_2);
    //     request.setSslConfiguration(ssl_config);
    // }

    // content type
    request.setHeader(QNetworkRequest::ContentTypeHeader, request_.contentType());
    request.setAttribute(QNetworkRequest::RedirectPolicyAttribute,
                         QNetworkRequest::NoLessSafeRedirectPolicy);
    // 先加全局的
    for (auto it = global_headers_.constBegin(), end = global_headers_.constEnd(); it != end;
         it++) {
        if (!request_.headers().contains(it.key())) {
            request.setRawHeader(it.key().toUtf8(), it.value().toUtf8());
        }
    }
    // 后加自定义的
    for (auto it = request_.headers().constBegin(), end = request_.headers().constEnd(); it != end;
         it++) {
        request.setRawHeader(it.key().toUtf8(), it.value().toUtf8());
    }

    // set url
    request.setUrl(QUrl(baseutils::formatUrl(request_.url())));

    // 打印请求及其headers
    if (log_) {
        qDebug() << QString("request:").rightJustified(8) << request_.method() << request_.url();
        qDebug() << QString("data:").rightJustified(8) << request_.data();
        const QList<QByteArray>& names = request.rawHeaderList();
        for (const QByteArray& n : names) {
            qDebug() << QString("         ") << n << request.rawHeader(n);
        }
    }

    // send
    // request.setHeader(QNetworkRequest::ContentLengthHeader, ba.length());
    int method = request_.method();
    switch (method) {
    case Request::GET_METHOD:
        reply_ = queue_->networkAccessManager().get(request, request_.data().toUtf8());
        break;
    case Request::PUT_METHOD:
        reply_ = queue_->networkAccessManager().put(request, request_.data().toUtf8());
        break;
    case Request::POST_METHOD: {
        if (request_.multiPart()) {
            reply_ = queue_->networkAccessManager().post(request, request_.multiPart().get());
        } else {
            reply_ = queue_->networkAccessManager().post(request, request_.data().toUtf8());
        }
        break;
    }
    case Request::DELETE_METHOD:
        reply_ = queue_->networkAccessManager().deleteResource(request);
        break;
    case Request::HEAD_METHOD:
        reply_ = queue_->networkAccessManager().head(request);
        break;
    default:
        break;
    }

    if (reply_) {
        QObject::connect(reply_, &QNetworkReply::finished, this, &RequestTask::onReplyFinished);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
        QObject::connect(reply_, &QNetworkReply::errorOccurred, this, &RequestTask::onReplyError);
#else
        QObject::connect(reply_, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error),
                         this, &RequestTask::onReplyError);
#endif
    }
}

void RequestTask::terminateImpl()
{
    abortReply();
}

void RequestTask::onTimeout()
{
    if (!completed_) {
        completed_ = true;
        // 终止请求
        abortReply();
        // 模拟超时响应回调
        Response resp(TIMEOUT_ERROR, tr("Timeout"));
        onResponse(request_, resp);
    }
}

void RequestTask::onReplyError(QNetworkReply::NetworkError error)
{
    if (isRunning() && !completed_) {
        completed_ = true;

        // 停止超时计时器
        stopTimeoutTimer();

        QString error_msg = reply_->errorString();
        QByteArray ba = reply_->readAll();
        if (!ba.isEmpty() && QJsonDocument::fromJson(ba).isObject()) {
            Response resp(ba, OK_CODE, error_msg);
            onResponse(request_, resp);
        } else {
            Response resp(error, error_msg);
            onResponse(request_, resp);
        }
        Q_EMIT failed(NETWORK_ERROR, reply_->errorString());
    }
}

void RequestTask::onReplyFinished()
{
    if (isRunning() && !completed_) {
        // 标记已经完成
        completed_ = true;

        // 停止超时计时器
        stopTimeoutTimer();

        QNetworkReply::NetworkError err = reply_->error();
        int status = OK_CODE;
        if (err != QNetworkReply::NoError) {
            status = SERVICE_ERROR;
        }
        QDateTime last_modified = reply_->header(QNetworkRequest::LastModifiedHeader).toDateTime();
        QByteArray data = reply_->readAll();
        reply_->deleteLater();
        reply_ = nullptr;

        Response resp(data, status, QString(), last_modified);
        onResponse(request_, resp);

        Q_EMIT finished();
    }
}

void RequestTask::onResponse(const Request& request, const Response& response)
{
    // 输出响应日志
    if (log_) {
        qDebug() << QString("reponse url:").rightJustified(12) << request.url()
                 << "elapsed time:" << elapsedMSecs() << "ms";
        qDebug() << QString("code:").rightJustified(12) << response.status()
                 << "message:" << response.msg();
        qDebug() << QString("data:").rightJustified(12) << QString::fromUtf8(response.rawData());
    }

    // 调用响应处理器
    handler_(request, response);

    if (response.status() == UNAUTHORIZED_ERROR) {
        Q_EMIT authenticationRequired();
    }
}

void RequestTask::abortReply()
{
    if (reply_) {
        disconnect(reply_, nullptr, this, nullptr);
        if (reply_->isRunning()) {
            reply_->abort();
        }
        delete reply_;
        reply_ = nullptr;
    }

    // 标记已经完成
    completed_ = true;
}

} // namespace yc
